/*
 * GLeague.java
 * Created on 18 juin 2007
 *
 * Glacéo Internet Platform
 * http://sourceforge.net/projects/chm/
 *
 * Copyright (c) 2005-2007, Jan Janke (VirtualHockey Project)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hockeo.vhbase.data.dao.contest;


import java.math.BigDecimal;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;

import com.hockeo.vhbase.conf.GRulesConstants;
import com.hockeo.vhbase.data.dao.IGEntity;
import com.hockeo.vhbase.data.dao.club.GClub;
import com.hockeo.vhbase.data.helper.GContestHistoryType;

/**
 * Represents a national hockey league.
 *
 * @version $Id$
 * @author jjanke
 */
@Entity
@DiscriminatorValue( "LEAGUE" )
public class GLeague extends GContest
{
  @Column( name = "nl_num_promoted_1" )
  private int         d_nNumPromoted1;

  @Column( name = "nl_num_promoted_2" )
  private int         d_nNumPromoted2;

  @Column( name = "nl_num_relegated" )
  private int         d_nNumRelegated;

  @OneToMany( mappedBy = "d_league" )
  @OrderBy( "d_nSeeding" )
  private List<GClub> d_listClubs;

  /**
   * Overridden to return the default implementation class name, if no specific one is
   * defined.
   */
  @Override
  public String getImplClass()
  {
    String strImplClass = super.getImplClass();

    if ( strImplClass == null )
      strImplClass = "defaultLeagueImpl";

    return strImplClass;
  }

  @Override
  public BigDecimal getRankingCoefficient()
  {
    switch ( getCategory() )
    {
      case 1: return GRulesConstants.CONTEST_COEFFICIENT_NATIONAL_LEAGUE_1;
      case 2: return GRulesConstants.CONTEST_COEFFICIENT_NATIONAL_LEAGUE_2;
      case 3: return GRulesConstants.CONTEST_COEFFICIENT_NATIONAL_LEAGUE_3;
      case 4: return GRulesConstants.CONTEST_COEFFICIENT_NATIONAL_LEAGUE_4;
      case 5: return GRulesConstants.CONTEST_COEFFICIENT_NATIONAL_LEAGUE_5;
      default:
        throw new IllegalStateException( "The league category " + getCategory() + " is not supported." );
    }
  }

  @Override
  public GContestHistoryType getHistoryType()
  {
    if ( getCategory() == 1 )
      return GContestHistoryType.NATIONAL_LEAGUE;
    else
      return GContestHistoryType.NATIONAL_MINOR_LEAGUE;
  }

  public int getNumPromoted1()
  {
    return d_nNumPromoted1;
  }

  public int getNumPromoted2()
  {
    return d_nNumPromoted2;
  }

  public int getNumRelegated()
  {
    return d_nNumRelegated;
  }

  /**
   * Returns all clubs that are currently attached to this league. The list is ordered
   * ascendingly by its national seeding list position.
   */
  public List<GClub> getClubs()
  {
    return d_listClubs;
  }

  /**
   * Returns the number of rounds that are played in this league. In one round each team
   * plays once against all the other teams (either at home or on the road). The number of
   * rounds to be played depends on the number of teams and is adjusted in such a way that
   * in each league there are between 18 and 30 matchdays. Ideally there should always be
   * an even number of rounds so that home and road games are equally distributed.
   *
   * @return the number of rounds to be played in this league
   */
  public int getNumRounds()
  {
    // Leagues with more than 16 teams are not supported (to play one round in a 16 team
    // league exactly 30 matchdays are required). Therefore we assert that the number of
    // teams is
    // always less than 17.
    //
    assert getNumTeams() < 17 : "The league has too many affiliated clubs (maximum is 16).";

    if ( getNumTeams() < 9 )
      return 4;
    else
      return 2;
  }

  /**
   * Returns the number of matches to be played by each team in the league.
   *
   * @return the number of matches per season for one team
   */
  public int getNumMatchesPerClub()
  {
    return ( getNumTeams() - 1 ) * getNumRounds();
  }

  /**
   * Returns the number of matchdays to be played in one season.
   *
   * @return the number of matchdays
   */
  public int getNumMatchdays()
  {
    final int nNumTeams = getNumTeams();

    if ( nNumTeams % 2 == 0 )
      return ( nNumTeams - 1 ) * getNumRounds();
    else
      return nNumTeams * getNumRounds();
  }

  /**
   * Returns the number of matches to be played per matchday.
   *
   * @return number of matches per matchday
   */
  public int getNumMatchesPerMatchday()
  {
    final int nNumTeams = getNumTeams();

    if ( nNumTeams % 2 == 0 )
      return nNumTeams / 2;
    else
      return ( nNumTeams - 1 ) / 2;
  }

  /**
   * A league consists of exactly one regular season contest element. This element is
   * returned by this method. It's just a convenience method so that it can be avoided to
   * traverse the contest hierarchy manually.
   *
   * @return the main round robin contest element of this league
   */
  public GRoundRobinContestElement getRegularSeasonElement()
  {
    assert !getContestRounds().isEmpty() : "No contest rounds defined for league " + getId();
    assert getContestRounds().get( 0 ).getContestElements().size() == 1 : "Exactly one element must be defined for the contest round "
        + getContestRounds().get( 0 ).getId();

    // The first contest element of a league must be a round robin contest element
    //
    return (GRoundRobinContestElement) getContestRounds().get( 0 ).getContestElements().get( 0 );
  }

  /**
   * Returns the ID of the unique regular season element.
   */
  public String getRegularSeasonElementId()
  {
    return getId() + "-1-1";
  }

  @Override
  public String getContestTypeIconPrefix()
  {
    return "league_";
  }

  public Class<? extends IGEntity> getGEntityClass()
  {
    return GLeague.class;
  }
}
